﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace System
{
    /// <summary>
    /// 整数型扩展方法
    /// </summary>
    [EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    public static class IntExtensions
    {
        #region Bool 判断
        /// <summary>
        /// 判断一个数值是否在指定范围内
        /// </summary>
        /// <param name="value"></param>
        /// <param name="minValue"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>
        public static bool InRange(this int value, int minValue, int maxValue)
        {
            return value >= minValue && value <= maxValue;
        }

        /// <summary>
        /// 返回数值是否为偶数
        /// Determines whether the value is even
        /// </summary>
        /// <param name = "value">The Value</param>
        /// <returns>true or false</returns>
        public static bool IsEven(this int value)
        {
            return value.AsLong().IsEven();
        }

        /// <summary>
        /// 返回数值是否为奇数
        /// Determines whether the value is odd
        /// </summary>
        /// <param name = "value">The Value</param>
        /// <returns>true or false</returns>
        public static bool IsOdd(this int value)
        {
            return value.AsLong().IsOdd();
        }

        /// <summary>
        /// 返回数值是否为素数
        /// A prime number (or a prime) is a natural number that has exactly two distinct natural number divisors: 1 and itself.
        /// </summary>
        /// <param name="candidate">Object value</param>
        /// <returns>Returns true if the value is a prime number.</returns>
        public static bool IsPrime(this int candidate)
        {
            return candidate.AsLong().IsPrime();
        }

        /// <summary>
        /// To check whether an index is in the range of the given array.
        /// </summary>
        /// <param name="index">Index to check</param>
        /// <param name="arrayToCheck">Array where to check</param>
        /// <returns></returns>
        /// <remarks>
        /// 	Contributed by Mohammad Rahman, http://mohammad-rahman.blogspot.com/
        /// </remarks>
        public static bool IsIndexInArray(this int index, Array arrayToCheck)
        {
            return index.GetArrayIndex().InRange(arrayToCheck.GetLowerBound(0), arrayToCheck.GetUpperBound(0));
        }
        #endregion //Bool 判断

        #region Convert 转换
        /// <summary>
        /// Returns the integer as long.
        /// </summary>
        public static long AsLong(this int i)
        {
            return i;
        }

        /// <summary>
        /// 返回序列字符串(英国-1st,2nd,3rd)
        /// Converts the value to ordinal string. (English)
        /// </summary>
        /// <param name="i">Object value</param>
        /// <returns>Returns string containing ordinal indicator adjacent to a numeral denoting. (English)</returns>
        public static string ToOrdinal(this int i)
        {
            return i.AsLong().ToOrdinal();
        }

        /// <summary>
        /// 
        /// Converts the value to ordinal string with specified format. (English)
        /// </summary>
        /// <param name="i">Object value</param>
        /// <param name="format">A standard or custom format string that is supported by the object to be formatted.</param>
        /// <returns>Returns string containing ordinal indicator adjacent to a numeral denoting. (English)</returns>
        public static string ToOrdinal(this int i, string format)
        {
            return i.AsLong().ToOrdinal(format);
        }
        #endregion //Convert 转换

        #region Get 获取
        /// <summary>
        /// 对数值进行上下限判定，返回限制范围内的数据
        /// </summary>
        /// <param name="value">当前值</param>
        /// <param name="min">最小值。如果 <paramref name="value"/> 小于此值， 则会返回最小值</param>
        /// <param name="max">最大值。如果 <paramref name="value"/> 大于此值， 则会返回最大值</param>
        /// <returns></returns>
        public static int LimitRange(this int value, int min, int max)
        {
            return value < min ? min : value > max ? max : value;
        }

        /// <summary>
        /// 返回大于或等于指定值商的最小数值
        /// </summary>
        /// <param name="value">被除数</param>
        /// <param name="divideBy">除数</param>
        /// <returns><see cref="T:System.Int32"/></returns>
        public static int CeilingDivide(this int value, int divideBy)
        {
            if (divideBy == 0) throw new ArgumentOutOfRangeException("divideBy");

            return (int)Math.Ceiling(value * 1.0 / divideBy);
        }

        /// <summary>
        /// 显示为字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToDisplayString(this int? value)
        {
            return value == null ? "" : value.ToString();
        }

        /// <summary>
        /// 显示为字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToDisplayString(this int? value, string defaultDisplayString)
        {
            return value == null ? defaultDisplayString : value.ToString();
        }

        /// <summary>
        /// To get Array index from a given based on a number.
        /// </summary>
        /// <param name="at">Real world postion </param>
        /// <returns></returns>
        /// <remarks>
        /// 	Contributed by Mohammad Rahman, http://mohammad-rahman.blogspot.com/
        /// 	jceddy fixed typo
        /// </remarks>
        public static int GetArrayIndex(this int at)
        {
            return at == 0 ? 0 : at - 1;
        }
        #endregion //Get 获取

        #region Memory Size 存储空间大小

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this ulong size)
        {
            return ((double)size).ToSizeDescription();
        }

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <param name="digits">小数位数</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this ulong size, int digits)
        {
            return ((double)size).ToSizeDescription(digits);
        }

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this long size)
        {
            return ((double)size).ToSizeDescription();
        }

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <param name="digits">小数位数</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this long size, int digits)
        {
            return ((double)size).ToSizeDescription(digits);
        }

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this int size)
        {
            return ((double)size).ToSizeDescription();
        }

        /// <summary>
        /// 转换为尺寸显示方式
        /// </summary>
        /// <param name="size">大小</param>
        /// <param name="digits">小数位数</param>
        /// <returns>尺寸显示方式</returns>
        public static string ToSizeDescription(this int size, int digits)
        {
            return ((double)size).ToSizeDescription(digits);
        }

        /// <summary>
        /// 限制数值的最小值, 当数值小于一定范围时, 则返回最小值
        /// </summary>
        /// <param name="value">当前数值</param>
        /// <param name="minValue">最小值</param>
        /// <returns>不小于 <paramref name="minValue"/> 的值</returns>
        public static int Min(this int value, int minValue)
        {
            return value < minValue ? minValue : value;
        }

        /// <summary>
        /// 限制数值的最大值, 当数值大于一定范围时, 则返回最大值
        /// </summary>
        /// <param name="value">当前数值</param>
        /// <param name="maxValue">最大值</param>
        /// <returns>不大于 <paramref name="maxValue"/> 的值</returns>
        public static int Max(this int value, int maxValue)
        {
            return value > maxValue ? maxValue : value;
        }

        #endregion Memory Size 存储空间大小

        #region INT的压缩

        private static readonly string _numberCode = GetInitialCodeString();

        /// <summary>
        /// 获得初始化字符串
        /// </summary>
        /// <returns></returns>
        internal static string GetInitialCodeString()
        {
            var array = new int[10 + 26 + 26];
            array.ForEachWithIndex((i, b) => array[i] = i < 10 ? 0x30 + i : (i < 10 + 26 ? (int)'A' + i - 10 : (int)'a' + i - 10 - 26));
            return new string(array.Select(s => (char)s).ToArray());
        }

        /// <summary>
        /// 将int压缩为字符串
        /// </summary>
        /// <param name="value">要压缩的 <see cref="T:System.Int32"/></param>
        /// <returns>压缩后的字符串</returns>
        public static string CompressToString(this int value)
        {
            var map = new List<char>();
            var step = _numberCode.Length;

            while (value > 0)
            {
                var digit = value % step;
                value = (value - digit) / step;
                map.Add(_numberCode[digit]);
            }

            return new string(map.Reverse<char>().ToArray());
        }

        /// <summary>
        /// 将字符串解压为Int值
        /// </summary>
        /// <param name="value">要解压的 <see cref="T:System.String"/></param>
        /// <returns>解压后的 <see cref="T:System.Int32"/></returns>
        public static int DecompressToInt(this string value)
        {
            var array = value.Select(s => _numberCode.IndexOf(s)).Reverse().ToArray();
            int result = 0;
            var step = 1;
            for (int i = 0; i < array.Length; i++)
            {
                result += array[i] * step;
                step *= _numberCode.Length;
            }

            return result;
        }

        #endregion INT的压缩


    }
}